#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/wait.h>
#include <sys/types.h>
#include<ctype.h>
#include<sys/stat.h>
#include<fcntl.h>
#define DELIM " \t"
//重定向模式
#define IN_DIR  1
#define OUT_DIR 2
#define APP_DIR 3

int quit=1;
int argc=0;
int lastcode=0;
char buff[1024];
char*argv[1024];
char pwd[1024];

//重定向后的文件夹名起始地址
char*redirlename=NULL;
//重定向模式
int redir_mode=0;

void check(char*cmd)
{
    //检查出ls -a  > log.txt
    //ls -a >> log.txt
    //ls -a < log.txt
    char *pos=cmd;
    while(*pos!='\0')
    {
        if(*pos=='>')
        {
            *pos++='\0';
            //1.>>  APP_DIR
            if(*pos=='>')
            {
                *pos++='\0';
                while(isspace(*pos)) pos++;  //跳过空格
                redirlename=pos;             //记录文件名起始地址
                redir_mode=APP_DIR;          //记录模式
                break;
            }
            //2.>  OUT_DIR
            else
            {
                while(isspace(*pos)) pos++;                 
                redirlename=pos;
                redir_mode=OUT_DIR;
                break;
            }
        }
        //3.< IN_DIR
        else if(*pos=='<')
        {
            *pos++='\0';
            while(isspace(*pos)) pos++;
            redirlename=pos;
            redir_mode=IN_DIR;
            break;
        }
        else
        {
            pos++;
        }
    }
}

int splitstring()
{
      //2.获取输入指令(包括空格)
      fgets(buff,sizeof(buff),stdin);
      
      //去除\n
      buff[strlen(buff)-1]='\0';
      //检查重定向
      check(buff);

      int i=1;  
      //切割strtok();
      argv[0]=strtok(buff,DELIM);
    
     while(1)
     {
         argv[i]=strtok(NULL,DELIM);
         if(argv[i]==NULL)
         {
             break;
         }
         else
         {
             i++;
         }
     }   
     return i;
}


//内建命令返回1 
//普通命令返回0
int buildcommand()
{
   //内建命令 cd
   if(argc==2&&strcmp(argv[0],"cd")==0)
   {
       //更改当前路径
       chdir(argv[1]);
       //获取当前最近的工作路径，然后更新给pwd
       getcwd(pwd,sizeof(pwd));
       printf("%s\n",pwd);
       return 1;
   }

   //实现echo  (退出码)
   else if(argc==2&&strcmp(argv[0],"echo")==0)
   {
       if(strcmp(argv[1],"$?")==0)
       {
           printf("%d\n",lastcode);
           lastcode=0;
       }
       /*
        else if(*argv[1] == '$')
        {
           char *val = getenv(argv[1]+1);
           if(val) printf("%s\n", val);
        }
        */
        else 
        {
            printf("%s\n",argv[1]);
        }
        return 1;
   }
    //配个色
    if(strcmp(argv[0], "ls") == 0)
    {
        argv[argc++] = "--color";
        argv[argc] = NULL;
    }
    return 0; 
}

//执行命令
int Execute()
{
    pid_t id=fork();
    if(id<0)
    {
        perror("fork");
        return -1;
    }
    //调用对应进程
    else if(id==0)
    {
        if(redir_mode==OUT_DIR)
        {
            int fd=open(redirlename,O_WRONLY|O_CREAT|O_TRUNC,0666);  
            dup2(fd,1);
        }
        else if(redir_mode==IN_DIR)
        {
            int fd=open(redirlename,O_RDONLY);
            dup2(fd,0);
        }
        else
        {
            int fd=open(redirlename,O_WRONLY|O_APPEND|O_CREAT,0666);
            dup2(fd,1);
        }
        execvp(argv[0],argv);
        exit(-1);//出问题时返回退出码-1
    }
    //父进程
    else 
    {
        int status =0;
        pid_t rid=waitpid(id,&status,0);

        if(rid==id)
        {
            //父进程记录最近一个进程的退出码
            lastcode=WEXITSTATUS(status);
        }

    }
    return 0;
}


//[teacher2345@localhost linux]$
int main()
{
    while(quit)
    {
        redirlename=NULL;
        redir_mode=0;

       //1.显示
       getcwd(pwd,sizeof(pwd));
      printf("[%s@localhost %s]$",getenv("USER"),pwd);

      //2.获取输入指令(包括空格)
        argc=splitstring();// (检查重定向)
      //3.判断命令是否内建命令
      int n=buildcommand();
     //4.执行命令
      if(n==0) 
         Execute();

     int j=0;
     for(j=0;j<argc;j++)
     {
         printf("[%d]->%s\n",j,argv[j]);
     }

    }
    return 0;
}
